﻿using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Version2
{
    public class BingGeoCodeAPI
    {

        private static Dictionary<string, string> codedAddrs = null;
        private static ILog logger = LogManager.GetLogger(typeof(BingGeoCodeAPI));

        /// <summary>
        /// Using BingAPI to geocode the address given.
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public static Double[] GeocodeAddress(string address)
        {
            address = address.ToUpper();
            string code;
            if (getCodedAddrs().TryGetValue(address, out code))
            {
                return new Double[] { Double.Parse(code.Split(',')[0]), Double.Parse(code.Split(',')[1]) };
            }

            logger.Debug(String.Format("Have not precoded \"{0}\", geocoding now.", address));
            string key = "AloaQ-IdbmQ-404BuzyqxUmAihnb1mCR42PvMXYtpaR_UNWeiNhy7Uh2U9ESl-LA";
            BingMapsAPI.GeocodeRequest geocodeRequest = new BingMapsAPI.GeocodeRequest();

            // Set the credentials using a valid Bing Maps key
            geocodeRequest.Credentials = new BingMapsAPI.Credentials();
            geocodeRequest.Credentials.ApplicationId = key;

            // Set the full address query
            geocodeRequest.Query = address;

            // Set the options to only return high confidence results 
            BingMapsAPI.ConfidenceFilter[] filters = new BingMapsAPI.ConfidenceFilter[1];
            filters[0] = new BingMapsAPI.ConfidenceFilter();
            filters[0].MinimumConfidence = BingMapsAPI.Confidence.High;

            // Add the filters to the options
            BingMapsAPI.GeocodeOptions geocodeOptions = new BingMapsAPI.GeocodeOptions();
            geocodeOptions.Filters = filters;
            geocodeRequest.Options = geocodeOptions;

            // Make the geocode request
            BingMapsAPI.GeocodeServiceClient geocodeService = new BingMapsAPI.GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
            BingMapsAPI.GeocodeResponse geocodeResponse = geocodeService.Geocode(geocodeRequest);

            if (geocodeResponse.Results.Length > 0)
            {
                writeToFile(address, geocodeResponse.Results[0].Locations[0].Latitude + "," + geocodeResponse.Results[0].Locations[0].Longitude);
                return new Double[] { geocodeResponse.Results[0].Locations[0].Latitude, geocodeResponse.Results[0].Locations[0].Longitude };
            }
            else
                throw new Exception("No Results Found");
        }


        private static Dictionary<string, string> getCodedAddrs()
        {
            if (codedAddrs == null)
            {
                codedAddrs = new Dictionary<string, string>();
                string line = null;
                System.IO.StreamReader file = null;
                try
                {
                    file = new System.IO.StreamReader(@".\codedaddresses.txt");
                    while ((line = file.ReadLine()) != null)
                    {
                        logger.Debug("Reading in: \"" + line + "\" to geocoded address map.");
                        string[] parts = line.Split(':');
                        codedAddrs.Add(parts[0], parts[1]);
                    }
                }
                catch (Exception e)
                {
                    e.ToString();
                }
                finally
                {
                    if (file != null)
                        file.Close();
                }
            }
            return codedAddrs;
        }

        /// <summary>
        /// Appends the address to the address file.
        /// </summary>
        /// <param name="address"></param>
        private static void writeToFile(String address, String lat_lon)
        {
            address = address.Replace(":", " ");
            using (System.IO.StreamWriter file = new System.IO.StreamWriter(@".\codedaddresses.txt", true))
            {
                file.WriteLine(address + ":" + lat_lon);
                getCodedAddrs().Add(address, lat_lon);
            }
        }

    }
}
